package org.dtrd.modules.flup.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.dtrd.common.system.vo.LoginUser;
import org.dtrd.common.util.DateUtils;
import org.dtrd.config.system.Constant;
import org.dtrd.config.system.Constant.FlupStatus;
import org.dtrd.config.wechat.api.impl.WechatApi;
import org.dtrd.config.wechat.entity.bean.officialaccount.template.ServiceStateMsg;
import org.dtrd.modules.doctor.entity.po.DtrdEntRdDoctor;
import org.dtrd.modules.doctor.service.IDtrdEntRdDoctorService;
import org.dtrd.modules.flup.entity.bean.*;
import org.dtrd.modules.flup.entity.po.DtrdEntRdFlupAppointmentRecord;
import org.dtrd.modules.flup.entity.po.DtrdEntRdFlupEvaluation;
import org.dtrd.modules.flup.entity.po.DtrdRlFlupProjectRecord;
import org.dtrd.modules.flup.entity.po.DtrdRlFlupTemplateProject;
import org.dtrd.modules.flup.entity.request.FlupAppointmentRecordListRequest;
import org.dtrd.modules.flup.entity.request.FlupAppointmentRecordPageRequest;
import org.dtrd.modules.flup.entity.request.PatientFlup;
import org.dtrd.modules.flup.mapper.DtrdEntRdFlupAppointmentRecordMapper;
import org.dtrd.modules.flup.service.*;
import org.dtrd.modules.organization.service.IDtrdEntRdOrganizationService;
import org.dtrd.modules.patient.entity.po.DtrdEntRdPatient;
import org.dtrd.modules.patient.service.IDtrdEntRdPatientService;
import org.dtrd.modules.system.service.ISysUserService;
import org.dtrd.modules.util.ShiroUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.toList;


/**
 * <p>
 * 复诊预约记录 服务实现类
 * </p>
 *
 * @author QR
 * @since 2021-12-16
 */
@DS("multi-datasource1")
@Service
@Slf4j
public class DtrdEntRdFlupAppointmentRecordServiceImpl extends ServiceImpl<DtrdEntRdFlupAppointmentRecordMapper, DtrdEntRdFlupAppointmentRecord> implements IDtrdEntRdFlupAppointmentRecordService {

    @Autowired
    private IDtrdEntRdPatientService patientService;
    @Autowired
    private IDtrdEntRdDoctorService doctorService;
    @Autowired
    private ISysUserService sysUserService;
    @Autowired
    private IDtrdEntRdOrganizationService organizationService;
    @Autowired
    private IDtrdEntRdFlupTemplateProjectService templateProjectService;
    @Autowired
    private IDtrdRlFlupProjectRecordService flupProjectRecordRlService;
    @Autowired
    private IDtrdEntRdFlupEvaluationService flupEvaluationService;
    @Autowired
    private IDtrdRlFlupTemplateProjectService templateProjectRlService;
    @Autowired
    private IDtrdEntRdFlupTemplateProjectService projectService;

    @Autowired
    private WechatApi wechatApi;

    @Override
    public List<DoctorFlupDaily> getFlupAppointmentRecordList(FlupAppointmentRecordListRequest request, Date startDate) {
        Integer doctorId = request.getDoctorId();
        Date endDate = DateUtils.nextMonth(startDate);
        LambdaQueryWrapper<DtrdEntRdFlupAppointmentRecord> queryWrapper = baseQueryWrapper()
                .eq(DtrdEntRdFlupAppointmentRecord::getDoctorId, doctorId)
                .ge(DtrdEntRdFlupAppointmentRecord::getFlupDate, startDate)
                .le(DtrdEntRdFlupAppointmentRecord::getFlupDate, endDate);
        List<DtrdEntRdFlupAppointmentRecord> poList = list(queryWrapper);
        // 没有记录返回null
        if (CollectionUtil.isEmpty(poList)) {
            return null;
        }
        // 转换成 date : poList 的格式
        Map<Date, List<DtrdEntRdFlupAppointmentRecord>> dateToRecord = poList.stream()
                .collect(groupingBy(DtrdEntRdFlupAppointmentRecord::getFlupDate, toList()));
        // 今天日期的字符串格式
        String today = DateUtils.formatDate(new Date(), DateUtils.MM_dd.get().toPattern());
        // 设置返回的列表
        List<DoctorFlupDaily> doctorFlupDailies = new ArrayList<>(dateToRecord.size());
        Set<Date> dates = dateToRecord.keySet();
        for (Date date : dates) {
            DoctorFlupDaily doctorFlupDaily = new DoctorFlupDaily();
            // 设置日期
            doctorFlupDaily.setDate(DateUtils.formatDate(date, DateUtils.MM_dd.get().toPattern()));
            doctorFlupDaily.setQueryDate(date);
            if (doctorFlupDaily.getDate().equals(today)) {
                doctorFlupDaily.setToday(true);
            }
            List<DtrdEntRdFlupAppointmentRecord> records = dateToRecord.get(date);
            // 设置人数
            doctorFlupDaily.setCount(records.size());
            // 设置患者内容
            List<PatientFlupInfo> patientFlupInfoList = new ArrayList<>(records.size());
            for (DtrdEntRdFlupAppointmentRecord record : records) {
                PatientFlupInfo patientFlupInfo = new PatientFlupInfo();
                patientFlupInfo.parseFromPo(record);
                String orgCode = record.getOrgCode();
                if (StrUtil.isNotBlank(orgCode)) {
                    patientFlupInfo.setOrganization(organizationService.getOrgName(orgCode));
                }
                patientFlupInfo.parseFromPo(patientService.getById(record.getPatientId()));
                patientFlupInfoList.add(patientFlupInfo);
            }
            if (DateUtils.isFuture(date)) {
                doctorFlupDaily.setStatus(Constant.FlupStatus.WaitToVisit.getStatus());
            }
            doctorFlupDaily.setPatientFlupInfoList(patientFlupInfoList);
            // 添加一日的数据
            doctorFlupDailies.add(doctorFlupDaily);
        }
        doctorFlupDailies.sort(Comparator.comparing(DoctorFlupDaily::getDate, Comparator.reverseOrder()));
        // 把今日的记录替换到列表 索引=0 处
        for (int i = 0; i < doctorFlupDailies.size(); i++) {
            if (doctorFlupDailies.get(i).isToday() && i != 0) {
                DoctorFlupDaily oldFirst = doctorFlupDailies.get(0);
                doctorFlupDailies.set(0, doctorFlupDailies.get(i));
                doctorFlupDailies.set(i, oldFirst);
            }
        }
        return doctorFlupDailies;
    }

    @Override
    public IPage<FlupAppointmentRecordListInfo> pageFlupAppointmentRecord(FlupAppointmentRecordPageRequest request) {
        LambdaQueryWrapper<DtrdEntRdFlupAppointmentRecord> queryWrapper = baseQueryWrapper();
        IPage<DtrdEntRdFlupAppointmentRecord> page = new Page<>(request.getPageNum(), request.getPageSize());
        page = this.page(page, queryWrapper);
        return page.convert(FlupAppointmentRecordListInfo::new);
    }

    @Override
    public FlupAppointmentRecordDetail getFlupAppointmentRecord(Integer dataId) {
        DtrdEntRdFlupAppointmentRecord dtrdEntRdFlupAppointmentRecord = getById(dataId);
        return Optional.ofNullable(dtrdEntRdFlupAppointmentRecord)
                .map(po -> new FlupAppointmentRecordDetail().parseFromPo(po))
                .orElse(null);
    }

    @Override
    public boolean saveOrUpdateFlupAppointmentRecord(FlupAppointmentRecordDetail dto) {
        DtrdEntRdFlupAppointmentRecord dtrdEntRdFlupAppointmentRecord = new DtrdEntRdFlupAppointmentRecord();
        if (dto.getDataId() == null) {
            dtrdEntRdFlupAppointmentRecord = dtrdEntRdFlupAppointmentRecord.init();
        }
        dtrdEntRdFlupAppointmentRecord.parseFromDto(dto);
        return saveOrUpdate(dtrdEntRdFlupAppointmentRecord);
    }

    @Override
    public boolean removeFlupAppointmentRecord(Integer dataId) {
        return removeById(dataId);
    }

    @Override
    public boolean hasTemplateLinkPatient(Integer templateId) {
        // 已预约，复诊中，待复诊三个状态下关联的模版
        LambdaQueryWrapper<DtrdEntRdFlupAppointmentRecord> queryWrapper = baseQueryWrapper()
                .eq(DtrdEntRdFlupAppointmentRecord::getFlupTemplateId, templateId)
                .in(DtrdEntRdFlupAppointmentRecord::getFlupStatus,
                        Constant.FlupStatus.HasAppointment.getStatus(),
                        Constant.FlupStatus.Visiting.getStatus(),
                        Constant.FlupStatus.WaitToVisit.getStatus()
                );
        List<DtrdEntRdFlupAppointmentRecord> list = this.list(queryWrapper);
        return CollectionUtil.isNotEmpty(list);
    }

    @Override
    public FlupRecord getPatientFlupRecordThisWeek(Integer patientId) {
        // 获取本周周一和周末的日期
        List<Date> weekDate = DateUtils.getWeekDate(new Date());
        Date startDate = weekDate.get(0);
        Date endDate = weekDate.get(6);
        LambdaQueryWrapper<DtrdEntRdFlupAppointmentRecord> queryWrapper = baseQueryWrapper()
                .eq(DtrdEntRdFlupAppointmentRecord::getPatientId, patientId)
                .ge(DtrdEntRdFlupAppointmentRecord::getFlupDate, startDate)
                .le(DtrdEntRdFlupAppointmentRecord::getFlupDate, endDate)
                // 本周内最新的复诊记录
                .orderByDesc(DtrdEntRdFlupAppointmentRecord::getFlupDate)
                .last("limit 1");
        DtrdEntRdFlupAppointmentRecord record = this.getOne(queryWrapper);
        return Optional.ofNullable(record)
                .map(FlupRecord::new)
                .orElse(null);
    }

    @Override
    public FlupRecord getPatientFlupRecordLatest(Integer patientId) {
        LambdaQueryWrapper<DtrdEntRdFlupAppointmentRecord> queryWrapper = baseQueryWrapper()
                .eq(DtrdEntRdFlupAppointmentRecord::getPatientId, patientId)
                .orderByDesc(DtrdEntRdFlupAppointmentRecord::getFlupDate)
                .last("limit 1");
        DtrdEntRdFlupAppointmentRecord record = this.getOne(queryWrapper);
        return Optional.ofNullable(record)
                .map(FlupRecord::new)
                .orElse(null);
    }

    @Override
    public FlupRecord getPatientFlupRecordStartOfThisWeek(Integer patientId) {
        Date monday = DateUtils.getMondayThisWeek();
        LambdaQueryWrapper<DtrdEntRdFlupAppointmentRecord> queryWrapper = baseQueryWrapper()
                .eq(DtrdEntRdFlupAppointmentRecord::getPatientId, patientId)
                .ge(DtrdEntRdFlupAppointmentRecord::getFlupDate, monday)
                .orderByDesc(DtrdEntRdFlupAppointmentRecord::getFlupDate)
                .last("limit 1");
        DtrdEntRdFlupAppointmentRecord record = this.getOne(queryWrapper);
        return Optional.ofNullable(record)
                .map(FlupRecord::new)
                .orElse(null);
    }

    @Override
    public List<FlupAppointmentRecordDetail> listPatientFlupRecord(Integer patientId, Date startDate, Date endDate) {
        LambdaQueryWrapper<DtrdEntRdFlupAppointmentRecord> queryWrapper = baseQueryWrapper()
                .eq(DtrdEntRdFlupAppointmentRecord::getPatientId, patientId)
                .ge(DtrdEntRdFlupAppointmentRecord::getFlupDate, startDate)
                .le(DtrdEntRdFlupAppointmentRecord::getFlupDate, endDate);
        List<DtrdEntRdFlupAppointmentRecord> list = this.list(queryWrapper);
        return Optional.ofNullable(list)
                .map(poList -> poList.stream()
                        .map(po -> new FlupAppointmentRecordDetail().parseFromPo(po))
                        .collect(Collectors.toList()))
                .orElse(null);
    }

    @Override
    public boolean hasPatientUnfinishedFlupRecord(Integer patientId) {
        // 患者在没有完成预约的情况下是 已预约 复诊中 待复诊的状态只有一条 所以此处有用 getOne
        LambdaQueryWrapper<DtrdEntRdFlupAppointmentRecord> queryWrapper = baseQueryWrapper()
                .eq(DtrdEntRdFlupAppointmentRecord::getPatientId, patientId)
                .in(DtrdEntRdFlupAppointmentRecord::getFlupStatus,
                        Constant.FlupStatus.HasAppointment.getStatus(),
                        Constant.FlupStatus.Visiting.getStatus(),
                        Constant.FlupStatus.WaitToVisit.getStatus()
                );
        DtrdEntRdFlupAppointmentRecord record = this.getOne(queryWrapper);
        return Optional.ofNullable(record).isPresent();
    }

    @Override
    public boolean hasPatientFinishedFlupRecordThisWeek(Integer patientId) {
        // 本周的时间范围
        List<Date> weekDate = DateUtils.getWeekDate(new Date());
        Date startDate = weekDate.get(0);
        Date endDate = weekDate.get(6);
        LambdaQueryWrapper<DtrdEntRdFlupAppointmentRecord> queryWrapper = baseQueryWrapper()
                .eq(DtrdEntRdFlupAppointmentRecord::getPatientId, patientId)
                .ge(DtrdEntRdFlupAppointmentRecord::getFlupDate, startDate)
                .le(DtrdEntRdFlupAppointmentRecord::getFlupDate, endDate)
                // 已完成的状态
                .eq(DtrdEntRdFlupAppointmentRecord::getFlupStatus, Constant.FlupStatus.HadVisited.getStatus())
                .orderByDesc(DtrdEntRdFlupAppointmentRecord::getFlupDate)
                .last("limit 1");
        DtrdEntRdFlupAppointmentRecord record = this.getOne(queryWrapper);
        return Optional.ofNullable(record).isPresent();
    }

    @Override
    public List<FlupAppointmentRecordDetail> getPatientFlupThisWeek(Integer patientId) {
        List<Date> weekDate = DateUtils.getWeekDate(new Date());
        Date startDate = weekDate.get(0);
        Date endDate = weekDate.get(6);
        return listPatientFlupRecord(patientId, startDate, endDate);
    }

    @Override
    public int countPatientWeekly(Integer doctorId, Date startDate, Date endDate) {
        return baseMapper.selectPatientByDateRange(doctorId, startDate, endDate);
    }

    @Override
    public List<AppointmentDoctorInfo> getDoctorFlupScheduleByDateRange(Date startDate, Date endDate, Integer doctorId) {
        List<AppointmentDoctorInfo> appointmentDoctorList = getAppointmentDoctorList(doctorId);
        appointmentDoctorList.forEach(doctorInfo -> {
            LambdaQueryWrapper<DtrdEntRdFlupAppointmentRecord> queryWrapper = baseQueryWrapper()
                    .eq(DtrdEntRdFlupAppointmentRecord::getDoctorId, doctorId)
                    .ge(DtrdEntRdFlupAppointmentRecord::getFlupDate, startDate)
                    .le(DtrdEntRdFlupAppointmentRecord::getFlupDate, endDate);
            List<DtrdEntRdFlupAppointmentRecord> poList = this.list(queryWrapper);
            // 转换成 date : poList 的格式
            Map<Date, List<DtrdEntRdFlupAppointmentRecord>> dateToRecord = poList.stream()
                    .collect(groupingBy(DtrdEntRdFlupAppointmentRecord::getFlupDate, toList()));
            // 今天日期的字符串格式
            String today = DateUtils.formatDate(new Date(), DateUtils.MM_dd.get().toPattern());
            // 设置返回的列表
            List<DoctorFlupDaily> doctorFlupDailies = new ArrayList<>(dateToRecord.size());
            Set<Date> dates = dateToRecord.keySet();
            for (Date date : dates) {
                DoctorFlupDaily doctorFlupDaily = new DoctorFlupDaily();
                // 设置日期
                doctorFlupDaily.setDate(DateUtils.formatDate(date, DateUtils.MM_dd.get().toPattern()));
                if (doctorFlupDaily.getDate().equals(today)) {
                    doctorFlupDaily.setToday(true);
                }
                List<DtrdEntRdFlupAppointmentRecord> records = dateToRecord.get(date);
                // 设置人数
                doctorFlupDaily.setCount(records.size());
                // 设置患者内容
                List<PatientFlupInfo> patientFlupInfoList = new ArrayList<>(records.size());
                records.stream().map(PatientFlupInfo::new).forEach(info -> {
                    DtrdEntRdPatient patient = patientService.getById(info.getPatientId());
                    if (patient != null) {
                        info.parseFromPo(patient);
                    } else {
                        info.setName("用户已注销");
                    }
                    patientFlupInfoList.add(info);
                });

                if (DateUtils.isFuture(date)) {
                    doctorFlupDaily.setStatus(Constant.FlupStatus.WaitToVisit.getStatus());
                }
                doctorFlupDaily.setPatientFlupInfoList(patientFlupInfoList);
                // 添加一日的数据
                doctorFlupDailies.add(doctorFlupDaily);
            }
            doctorInfo.setFlupRecord(doctorFlupDailies);
        });
        return appointmentDoctorList;
    }

    @Override
    public List<AppointmentDoctorInfo> getAppointmentDoctorList(Integer doctorId) {
        LambdaQueryWrapper<DtrdEntRdDoctor> wrapper = Wrappers.lambdaQuery(DtrdEntRdDoctor.class)
                .eq(DtrdEntRdDoctor::getDataId, doctorId);
        List<DtrdEntRdDoctor> doctors = doctorService.list(wrapper);
        List<AppointmentDoctorInfo> doctorInfos = null;
        if (CollectionUtil.isNotEmpty(doctors)) {
            doctorInfos = doctors.stream().map(AppointmentDoctorInfo::new).collect(Collectors.toList());
        }
        return doctorInfos;
    }

    @Override
    public boolean savePatientFlup(PatientFlup patientFlup) {
        DtrdEntRdFlupAppointmentRecord appointmentRecord = new DtrdEntRdFlupAppointmentRecord().parseFromDto(patientFlup);
        // 设置复诊状态, 如果是今天直接设置待复诊状态，否则设置为已预约
        Date date = patientFlup.getFlupDateDate();
        if (DateUtils.isToday(date)) {
            appointmentRecord.setFlupStatus(Constant.FlupStatus.WaitToVisit.getStatus());
        } else {
            appointmentRecord.setFlupStatus(Constant.FlupStatus.HasAppointment.getStatus());
        }
        boolean result = saveOrUpdate(appointmentRecord);
        // 生成复诊流程内容
        Integer flupId = appointmentRecord.getDataId();
        Integer templateId = patientFlup.getTemplateId();
        // 如果是更新先删除原来的复诊流程内容
        if (patientFlup.getDataId() != null) {
            flupProjectRecordRlService.removeFlupFlow(flupId);
        }
        flupProjectRecordRlService.createFlupFlow(flupId, templateId);
        sendFlupAppointMsg(patientFlup.getPatientId(), appointmentRecord.getDataId(), patientFlup.getFlupDate(), false);
        return result;
    }

    /**
     * 发送复诊预约或复诊成功消息
     *
     * @param patientId 患者ID
     * @param flupId    复诊记录ID
     * @param flupDate  复诊日期
     * @param isFinish  是否完成
     */
    private void sendFlupAppointMsg(Integer patientId, Integer flupId, String flupDate, boolean isFinish) {
        // 添加复诊预约成功消息推送 肖  2022-05-31 17:36:33
        DtrdEntRdPatient patient = patientService.getById(patientId);
        if (patient == null) {
            return;
        }
        if (patient.getDoctorId() != null) {
            // 发送给医生 患者关联的医生非空
            DtrdEntRdDoctor doctor = doctorService.getById(patient.getDoctorId());
            if (doctor.getWxOaOpenid() != null) {
                String patientName = StrUtil.isBlank(patient.getPatientsName()) ? patient.getPatientsMobile() : patient.getPatientsName();
                ServiceStateMsg msg;
                if (isFinish) {
                    msg = ServiceStateMsg.ServiceStateMsgBuilder.singleInstance()
                            .buildFlupAppointFinishForDoctor(patientName, patientId,doctor.getDataId(), flupId)
                            .build();
                } else {
                    msg = ServiceStateMsg.ServiceStateMsgBuilder.singleInstance()
                            .buildFlupAppointForDoctor(patientName, flupDate, patient.getDataId(), flupId)
                            .build();
                }
                wechatApi.appointmentSucceed(msg, doctor.getWxOaOpenid());
            }
        }
        // 发送给患者
        if (patient.getWxOaOpenid() != null) {
            ServiceStateMsg msg;
            if (isFinish) {
                msg = ServiceStateMsg.ServiceStateMsgBuilder.singleInstance()
                        .buildFlupAppointFinishForPatient(patientId, flupId)
                        .build();
            } else {
                msg = ServiceStateMsg.ServiceStateMsgBuilder.singleInstance()
                        .buildFlupAppointForPatient(flupDate, patientId, flupId)
                        .build();
            }
            wechatApi.appointmentSucceed(msg, patient.getWxOaOpenid());
        }

    }


    @Override
    public IPage<PatientFlupListInfo> pagePatientFlup(Integer patientId, Date startDate, Date endDate, Integer page, Integer pageSize) {
        LambdaQueryWrapper<DtrdEntRdFlupAppointmentRecord> queryWrapper = Wrappers.lambdaQuery(DtrdEntRdFlupAppointmentRecord.class)
                .eq(DtrdEntRdFlupAppointmentRecord::getPatientId, patientId)
                .in(DtrdEntRdFlupAppointmentRecord::getFlupStatus,
                        Constant.FlupStatus.WaitToVisit.getStatus(),
                        Constant.FlupStatus.HadVisited.getStatus(),
                        Constant.FlupStatus.NotVisited.getStatus(),
                        Constant.FlupStatus.Visiting.getStatus(),
                        FlupStatus.HasAppointment.getStatus())
                .orderByDesc(DtrdEntRdFlupAppointmentRecord::getFlupDate);
        if (startDate != null && endDate != null) {
            queryWrapper
                    .ge(DtrdEntRdFlupAppointmentRecord::getFlupDate, startDate)
                    .lt(DtrdEntRdFlupAppointmentRecord::getFlupDate, endDate);
        }
        IPage<DtrdEntRdFlupAppointmentRecord> queryPage = new Page<>(page, pageSize);
        queryPage = this.page(queryPage, queryWrapper);
        return queryPage.convert(po -> {
            PatientFlupListInfo dto = new PatientFlupListInfo().parseFromPo(po);
            String receiver = sysUserService.getRealNameByUserName(po.getReceiver());
            Optional.ofNullable(receiver).ifPresent(dto::setReceiver);
            dto.setDoctorName(doctorService.getDoctorName(po.getDoctorId()));
            // TODO 暂时移除 机构名称查询
//            dto.setOrganization(organizationService.getOrgName(po.getOrgCode()));
            return dto;
        });
    }

    @Override
    public FlupRecordDetail getFlupRecordDetail(Integer id) {
        DtrdEntRdFlupAppointmentRecord appointmentRecord = getById(id);
        if (appointmentRecord == null) {
            return null;
        }
        LambdaQueryWrapper<DtrdRlFlupProjectRecord> flupProjectRecordQueryWrapper = Wrappers.lambdaQuery(DtrdRlFlupProjectRecord.class)
                .eq(DtrdRlFlupProjectRecord::getFlupAppointmentId, id);
        List<DtrdRlFlupProjectRecord> flupProjectRecordList = flupProjectRecordRlService.list(flupProjectRecordQueryWrapper);
        // 获取复诊评价
        DtrdEntRdFlupEvaluation flupEvaluation = flupEvaluationService.getByFlupEvaluationFlupId(id);
        // 设置返回内容
        FlupRecordDetail detail = new FlupRecordDetail();
        // 预约数据
        detail.parseFromPo(appointmentRecord);
        // 项目数据
        if (CollectionUtil.isNotEmpty(flupProjectRecordList)) {
            Map<Integer, String> map = templateProjectService.getTemplateProjectIdToDetail(appointmentRecord.getFlupTemplateId());
            List<FlupProjectRecord> list = flupProjectRecordList.stream()
                    .map(po -> {
                        FlupProjectRecord record = new FlupProjectRecord().parseFromPO(po);
                        record.setOperator(sysUserService.getRealNameByUserName(po.getOperator()));
                        record.setProjectName(projectService.getProjectName(po.getProjectId()));
                        record.setProjectDetail(map.get(po.getProjectId()));
                        return record;
                    })
                    .collect(toList());
            detail.setProjectRecords(list);
        }
        // 患者评价
        if (flupEvaluation != null) {
            detail.parseFromPo(flupEvaluation);
        }
        return detail;
    }

    @Override
    public boolean hasProjectLinkPatient(Integer id) {
        // tp: templateProject
        LambdaQueryWrapper<DtrdRlFlupTemplateProject> tpQueryWrapper = Wrappers.lambdaQuery(DtrdRlFlupTemplateProject.class)
                .eq(DtrdRlFlupTemplateProject::getTemplateProjectId, id);
        List<DtrdRlFlupTemplateProject> templateProjects = templateProjectRlService.list(tpQueryWrapper);
        if (CollectionUtil.isEmpty(templateProjects)) {
            return false;
        }
        Optional<DtrdRlFlupTemplateProject> any = templateProjects.stream()
                .filter(rl -> hasTemplateLinkPatient(rl.getTemplateId()))
                .collect(toList())
                .stream().findAny();
        return any.isPresent();
    }

    @Override
    public boolean updatePatientFlupStatus(Integer flupId, Integer type, String content) {
        DtrdEntRdFlupAppointmentRecord record = this.getById(flupId);
        if (record == null) {
            return false;
        }
        switch (type) {
            case 1:
                record.setFlupStatus(Constant.FlupStatus.Visiting.getStatus());
                record.setFlupRealStartTime(new Date());
                break;
            case 2:
                record.setFlupStatus(Constant.FlupStatus.HadVisited.getStatus());
                record.setFlupRealEndTime(new Date());
                record.setFlupContent(content);
                //发送复诊成功消息
                sendFlupAppointMsg(record.getPatientId(), flupId, null, true);
                break;
            default:
                break;
        }
        return updateById(record);
    }

    @Override
    public boolean updatePatientFlupContent(Integer flupId, String content)
    {
        DtrdEntRdFlupAppointmentRecord record = this.getById(flupId);
        if (record == null) {
            return false;
        }
        record.setFlupContent(content);
        return updateById(record);
    }

    @Override
    @SuppressWarnings("unchecked")
    public List<FlupFlowItem> getFlupFlow(Integer flupId) {
        DtrdEntRdFlupAppointmentRecord appointmentRecord = this.getById(flupId);
        if (appointmentRecord == null) {
            return Collections.EMPTY_LIST;
        }
        // 查询复诊流程及内容
        LambdaQueryWrapper<DtrdRlFlupProjectRecord> wrapper = Wrappers.lambdaQuery(DtrdRlFlupProjectRecord.class)
                .eq(DtrdRlFlupProjectRecord::getFlupAppointmentId, flupId);
        List<DtrdRlFlupProjectRecord> list = flupProjectRecordRlService.list(wrapper);
        if (CollectionUtil.isEmpty(list)) {
            return Collections.EMPTY_LIST;
        }
        Map<Integer, String> map = templateProjectService.getTemplateProjectIdToDetail(appointmentRecord.getFlupTemplateId());
        return list.stream()
                .map(po -> {
                    FlupFlowItem item = new FlupFlowItem(po);
                    // 复诊详情
                    Integer projectId = po.getProjectId();
                    item.setProjectDetail(map.get(projectId));
                    // 操作人
                    String operator = po.getOperator();
                    if (StrUtil.isNotBlank(operator)) {
                        item.setExecutor(sysUserService.getRealNameByUserName(operator));
                    }
                    return item;
                })
                .collect(toList());
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean saveFlupFlow(List<FlupFlowItem> flupFlowItems, Integer flupId) {
        DtrdEntRdFlupAppointmentRecord appointmentRecord = getById(flupId);
        ArrayList<DtrdRlFlupProjectRecord> flupProjectRecords = new ArrayList<>(flupFlowItems.size());
        flupFlowItems.forEach(item -> {
            DtrdRlFlupProjectRecord record = new DtrdRlFlupProjectRecord();
            record.setFlupAppointmentId(flupId);
            record.setTemplateId(appointmentRecord.getFlupTemplateId());
            record.setProjectId(item.getProjectId());
            record.setProjectData(item.getProjectData());
            record.setProjectStatus(item.getProjectStatus());
            record.setProjectSuggest(item.getRemark());
            LoginUser loginUser = ShiroUtil.getLoginUser();
            if (loginUser != null) {
                record.setOperator(loginUser.getId());
            }
            flupProjectRecords.add(record);
        });
        for (DtrdRlFlupProjectRecord flupProjectRecord : flupProjectRecords) {
            // 根据 复诊记录id 和 模板项目id 设置新增或修改的条件
            LambdaQueryWrapper<DtrdRlFlupProjectRecord> wrapper = Wrappers.lambdaQuery(DtrdRlFlupProjectRecord.class)
                    .eq(DtrdRlFlupProjectRecord::getFlupAppointmentId, flupId)
                    .eq(DtrdRlFlupProjectRecord::getProjectId, flupProjectRecord.getProjectId());
            flupProjectRecordRlService.saveOrUpdate(flupProjectRecord, wrapper);
        }
        return true;
    }

    @Override
    public DoctorFlupDaily getDoctorFlupByDate(Integer doctorId, Date queryDate) {
        LambdaQueryWrapper<DtrdEntRdFlupAppointmentRecord> queryWrapper = baseQueryWrapper()
                .eq(DtrdEntRdFlupAppointmentRecord::getDoctorId, doctorId)
                .eq(DtrdEntRdFlupAppointmentRecord::getFlupDate, queryDate);
        List<DtrdEntRdFlupAppointmentRecord> poList = list(queryWrapper);
        // 没有记录返回null
        if (CollectionUtil.isEmpty(poList)) {
            return null;
        }
        DoctorFlupDaily doctorFlupDaily = new DoctorFlupDaily();
        // 设置日期
        doctorFlupDaily.setDate(DateUtils.formatDate(queryDate, DateUtils.MM_dd.get().toPattern()));
        doctorFlupDaily.setQueryDate(queryDate);
        // 设置患者内容
        List<PatientFlupInfo> patientFlupInfoList = new ArrayList<>(poList.size());
        for (DtrdEntRdFlupAppointmentRecord record : poList) {
            PatientFlupInfo patientFlupInfo = new PatientFlupInfo();
            patientFlupInfo.parseFromPo(record);
            patientFlupInfo.parseFromPo(patientService.getById(record.getPatientId()));
            patientFlupInfoList.add(patientFlupInfo);
        }
        doctorFlupDaily.setPatientFlupInfoList(patientFlupInfoList);
        doctorFlupDaily.setCount(patientFlupInfoList.size());
        return doctorFlupDaily;
    }

    @Override
    public String getPatientFlupQrCode(Integer patientId, Integer type) {
        String qrCode = "";
        // 查询患者信息
        DtrdEntRdPatient patient = patientService.getById(patientId);
        if (patient == null) {
            return qrCode;
        }
        Constant.QrCodeType qrCodeType = Constant.QrCodeType.valueOf(type);
        switch (qrCodeType) {
            case FlupReception:
                qrCode = patient.getFlupReceptionQrcode();
                break;
            case FlupFinished:
                qrCode = patient.getFlupFinishQrcode();
                break;
        }
        return qrCode;
    }

    @Override
    public FlupBasicInfo getFlupInfo(Integer flupId) {
        DtrdEntRdFlupAppointmentRecord record = getById(flupId);
        if (record == null) {
            return null;
        }
        FlupBasicInfo flupBasicInfo = new FlupBasicInfo();
        // 设置返回信息
        Date flupDate = record.getFlupDate();
        flupBasicInfo.setFlupDate(DateUtils.formatDate(flupDate, DateUtils.date_sdf.get().toPattern()));
        flupBasicInfo.setOrgName(organizationService.getOrgName(record.getOrgCode()));
        flupBasicInfo.setDoctorName(doctorService.getDoctorName(record.getDoctorId()));
        return flupBasicInfo;
    }

    @Override
    public Integer getPatientFlupStatus(Integer patientId) {
        FlupRecord flupRecord = getPatientFlupRecordThisWeek(patientId);
        return Optional.ofNullable(flupRecord)
                .map(FlupRecord::getFlupStatus)
                .orElse(Constant.FlupStatus.NoAppointment.getStatus());
    }

    @Override
    public Boolean currentTimeHasFlup(Integer doctorId, String flupDate, Integer flupTime) {
        LambdaQueryWrapper<DtrdEntRdFlupAppointmentRecord> queryWrapper = baseQueryWrapper()
                .eq(DtrdEntRdFlupAppointmentRecord::getDoctorId, doctorId)
                .eq(DtrdEntRdFlupAppointmentRecord::getFlupDate, DateUtil.parse(flupDate, DateUtils.date_sdf.get().toPattern()))
                .eq(DtrdEntRdFlupAppointmentRecord::getFlupTime, flupTime)
                .last("limit 1");
        DtrdEntRdFlupAppointmentRecord record = getOne(queryWrapper);
        // info.debug(record);
        return record != null;
    }

    @Override
    public void removeRecordByPatientIds(Set<Integer> patientIds) {
        if (CollectionUtil.isNotEmpty(patientIds)) {
            baseMapper.removeRecordByPatientIds(patientIds, FlupStatus.HasAppointment.getStatus(), FlupStatus.WaitToVisit.getStatus(), FlupStatus.NotVisited.getStatus());
        }
    }

    private LambdaQueryWrapper<DtrdEntRdFlupAppointmentRecord> baseQueryWrapper() {
        return Wrappers.lambdaQuery(DtrdEntRdFlupAppointmentRecord.class)
                .eq(DtrdEntRdFlupAppointmentRecord::getIsDel, 0);
    }

    private LambdaUpdateWrapper<DtrdEntRdFlupAppointmentRecord> baseUpdateWrapper() {
        return Wrappers.lambdaUpdate(DtrdEntRdFlupAppointmentRecord.class)
                .eq(DtrdEntRdFlupAppointmentRecord::getIsDel, 0);
    }

}
